package my.wechat.rc.common;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class JsonUtil {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true)
            .setSerializationInclusion(JsonInclude.Include.ALWAYS);

    private static final ObjectMapper OBJECT_MAPPER_NONE_EMPTY = new ObjectMapper()
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true)
            .setSerializationInclusion(JsonInclude.Include.NON_EMPTY);

    public static <T> T strToObj(String jsonStr, Class<T> clazz) {
        try {
            return OBJECT_MAPPER.readValue(jsonStr, clazz);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> String objToStr(T value) {
        try {
            return OBJECT_MAPPER.writeValueAsString(value);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> T objToObj(Object object, Class<T> clazz) {
        return OBJECT_MAPPER.convertValue(object, clazz);
    }

    public static <T> List<T> objToList(Object object, Class<T> clazz) {
        try {
            JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructParametricType(ArrayList.class, clazz);
            return OBJECT_MAPPER.readValue(objToStr(object), javaType);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> T inStreamToObj(InputStream in, Class<T> clazz) {
        try {
            return OBJECT_MAPPER.readValue(in, clazz);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * branch 覆盖 master, null 和 "" 无效
     */
    public static <T> T objMerge(Object master, Object branch, Class<T> clazz) {
        Map map1 = OBJECT_MAPPER_NONE_EMPTY.convertValue(master, Map.class);
        if (branch != null) {
            Map map2 = OBJECT_MAPPER_NONE_EMPTY.convertValue(branch, Map.class);
            map1.putAll(map2);
        }
        return OBJECT_MAPPER_NONE_EMPTY.convertValue(map1, clazz);
    }

    /**
     * branch 覆盖 master
     */
    public static <T> T objMergeReplace(Object master, Object branch, Class<T> clazz) {
        Map map1 = OBJECT_MAPPER.convertValue(master, Map.class);
        if (branch != null) {
            Map map2 = OBJECT_MAPPER.convertValue(branch, Map.class);
            map1.putAll(map2);
        }
        return OBJECT_MAPPER.convertValue(map1, clazz);
    }

}
